package cn.pixelsol.google.translate;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSONArray;

public class GoogleTransApi {

	private static final String PATH = "/gettk.js";
	private static ScriptEngine engine = null;
	private Browser browser = null;

	public enum FromLang {
		自动检测, 阿尔巴尼亚语, 阿拉伯语, 阿姆哈拉语, 阿塞拜疆语, 爱尔兰语, 爱沙尼亚语, 巴斯克语, 白俄罗斯语, 保加利亚语, 冰岛语, 波兰语, 波斯尼亚语, 波斯语, 布尔语_南非荷兰语, 丹麦语, 德语, 俄语,
		法语, 菲律宾语, 芬兰语, 弗里西语, 高棉语, 格鲁吉亚语, 古吉拉特语, 哈萨克语, 海地克里奥尔语, 韩语, 豪萨语, 荷兰语, 吉尔吉斯语, 加利西亚语, 加泰罗尼亚语, 捷克语, 卡纳达语, 科西嘉语,
		克罗地亚语, 库尔德语, 拉丁语, 拉脱维亚语, 老挝语, 立陶宛语, 卢森堡语, 罗马尼亚语, 马尔加什语, 马耳他语, 马拉地语, 马拉雅拉姆语, 马来语, 马其顿语, 毛利语, 蒙古语, 孟加拉语, 缅甸语, 苗语,
		南非科萨语, 南非祖鲁语, 尼泊尔语, 挪威语, 旁遮普语, 葡萄牙语, 普什图语, 齐切瓦语, 日语, 瑞典语, 萨摩亚语, 塞尔维亚语, 塞索托语, 僧伽罗语, 世界语, 斯洛伐克语, 斯洛文尼亚语, 斯瓦希里语,
		苏格兰盖尔语, 宿务语, 索马里语, 塔吉克语, 泰卢固语, 泰米尔语, 泰语, 土耳其语, 威尔士语, 乌尔都语, 乌克兰语, 乌兹别克语, 西班牙语, 希伯来语, 希腊语, 夏威夷语, 信德语, 匈牙利语, 修纳语,
		亚美尼亚语, 伊博语, 意大利语, 意第绪语, 印地语, 印尼巽他语, 印尼语, 印尼爪哇语, 英语, 约鲁巴语, 越南语, 中文
	}

	public enum ToLang {
		阿尔巴尼亚语, 阿拉伯语, 阿姆哈拉语, 阿塞拜疆语, 爱尔兰语, 爱沙尼亚语, 巴斯克语, 白俄罗斯语, 保加利亚语, 冰岛语, 波兰语, 波斯尼亚语, 波斯语, 布尔语_南非荷兰语, 丹麦语, 德语, 俄语, 法语,
		菲律宾语, 芬兰语, 弗里西语, 高棉语, 格鲁吉亚语, 古吉拉特语, 哈萨克语, 海地克里奥尔语, 韩语, 豪萨语, 荷兰语, 吉尔吉斯语, 加利西亚语, 加泰罗尼亚语, 捷克语, 卡纳达语, 科西嘉语, 克罗地亚语,
		库尔德语, 拉丁语, 拉脱维亚语, 老挝语, 立陶宛语, 卢森堡语, 罗马尼亚语, 马尔加什语, 马耳他语, 马拉地语, 马拉雅拉姆语, 马来语, 马其顿语, 毛利语, 蒙古语, 孟加拉语, 缅甸语, 苗语, 南非科萨语,
		南非祖鲁语, 尼泊尔语, 挪威语, 旁遮普语, 葡萄牙语, 普什图语, 齐切瓦语, 日语, 瑞典语, 萨摩亚语, 塞尔维亚语, 塞索托语, 僧伽罗语, 世界语, 斯洛伐克语, 斯洛文尼亚语, 斯瓦希里语, 苏格兰盖尔语,
		宿务语, 索马里语, 塔吉克语, 泰卢固语, 泰米尔语, 泰语, 土耳其语, 威尔士语, 乌尔都语, 乌克兰语, 乌兹别克语, 西班牙语, 希伯来语, 希腊语, 夏威夷语, 信德语, 匈牙利语, 修纳语, 亚美尼亚语,
		伊博语, 意大利语, 意第绪语, 印地语, 印尼巽他语, 印尼语, 印尼爪哇语, 英语, 约鲁巴语, 越南语, 中文_繁体, 中文_简体
	}

	static {
		ScriptEngineManager maneger = new ScriptEngineManager();
		engine = maneger.getEngineByName("javascript");
		FileInputStream fileInputStream = null;
		Reader scriptReader = null;
		try {
			scriptReader = new InputStreamReader(GoogleTransApi.class.getResourceAsStream(PATH), "utf-8");
			engine.eval(scriptReader);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fileInputStream != null) {
				try {
					fileInputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (scriptReader != null) {
				try {
					scriptReader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public GoogleTransApi() {
		this.browser = new Browser();
	}

	public GoogleTransApi(String ip, Integer port) {
		this.browser = new Browser();
		this.browser.setProxy(ip, port);
	}

	private String getTKK() {
		browser.setUrl("https://translate.google.cn/");
		try {
			String result = browser.executeGet();
			if (StringUtils.isNotBlank(result)) {
				if (result.indexOf("TKK") > -1) {
					String tkk = result.split("TKK")[1];
					tkk = tkk.split(";")[0];
					tkk = tkk.substring(2, tkk.length() - 1);
//                    ScriptEngineManager manager = new ScriptEngineManager();
//                    ScriptEngine engine = manager.getEngineByName("javascript");
//                    return (String) engine.eval(tkk);
					return tkk;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private static String getTK(String word, String tkk) {
		String result = null;
		try {
			if (engine instanceof Invocable) {
				Invocable invocable = (Invocable) engine;
				result = (String) invocable.invokeFunction("tk", new Object[] { word, tkk });
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 
	 * 翻译短文本（文本长度小于等于5000）
	 * 
	 * @param text 待翻译的文本
	 * @param from 待翻译文本语言
	 * @param to   翻译到的语言
	 * @return 翻译结果
	 * @throws IOException
	 */
	private String trans(String text, String from, String to) throws IOException {
		if (StringUtils.isBlank(text)) {
			return null;
		}
		String _tkk = getTKK();
		if (StringUtils.isBlank(_tkk)) {
			return null;
		}
		String _tk = getTK(text, _tkk);
		try {
			text = URLEncoder.encode(text, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		StringBuffer buffer = new StringBuffer("https://translate.google.cn/translate_a/single?client=t");
		buffer.append("&sl=" + from);
		buffer.append("&tl=" + to);
		buffer.append(
				"&hl=zh-CN&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&ie=UTF-8&oe=UTF-8&source=btn&kc=0");
		buffer.append("&tk=" + _tk);
		buffer.append("&q=" + text);
		browser.setUrl(buffer.toString());
		String result = browser.executeGet();
		if (result != null) {
			JSONArray array = (JSONArray) JSONArray.parse(result);
			JSONArray r_array = array.getJSONArray(0);
			StringBuffer r_buffer = new StringBuffer();
			for (int i = 0; i < r_array.size(); i++) {
				String _r = r_array.getJSONArray(i).getString(0);
				if (StringUtils.isNotBlank(_r)) {
					r_buffer.append(_r);
				}
			}
			return r_buffer.toString();
		}
		return null;
	}

	/**
	 * 翻译文本（支持翻译超长文本）
	 * 
	 * @param text 待翻译的文本
	 * @param from 待翻译文本语言
	 * @param to   翻译到的语言
	 * @return 翻译结果
	 * @throws IOException
	 */
	public String translate(String text, String from, String to) {
		int len = text.length();
		String result = "";
		List<String> strList = new ArrayList<String>();
		if (len > 5000) {
			int index = 0;
			while (index < len) {
				String str = "";
				if (index + 5000 <= len) {
					str = text.substring(index, index + 5000);
					index += 5000;
				} else {
					str = text.substring(index, len);
					index = len;
				}
				strList.add(str);
			}
		} else {
			strList.add(text);
		}
		for (String str : strList) {
			String ret;
			try {
				ret = trans(str, from, to);
				if (ret == null) {
					return null;
				}
				result += ret;
			} catch (IOException e) {
				System.err.println("GoogleApi：" + e.getMessage());
				return null;
			}
		}
		return result;
	}

	/**
	 * 翻译文本（支持翻译超长文本）
	 * 
	 * @param text 待翻译的文本
	 * @param from 待翻译文本语言
	 * @param to   翻译到的语言
	 * @return 翻译结果
	 * @throws IOException
	 */
	public String translate(String text, FromLang from, ToLang to) throws IOException {
		return (translate(text, getFromLang(from), getToLang(to)));
	}

	private Map<String, String> loadLanguage() {
		Map<String, String> language = new HashMap<String, String>();
		language.put("auto", "自动检测");
		language.put("sq", "阿尔巴尼亚语");
		language.put("ar", "阿拉伯语");
		language.put("am", "阿姆哈拉语");
		language.put("az", "阿塞拜疆语");
		language.put("ga", "爱尔兰语");
		language.put("et", "爱沙尼亚语");
		language.put("eu", "巴斯克语");
		language.put("be", "白俄罗斯语");
		language.put("bg", "保加利亚语");
		language.put("is", "冰岛语");
		language.put("pl", "波兰语");
		language.put("bs", "波斯尼亚语");
		language.put("fa", "波斯语");
		language.put("af", "布尔语_南非荷兰语");
		language.put("da", "丹麦语");
		language.put("de", "德语");
		language.put("ru", "俄语");
		language.put("fr", "法语");
		language.put("tl", "菲律宾语");
		language.put("fi", "芬兰语");
		language.put("fy", "弗里西语");
		language.put("km", "高棉语");
		language.put("ka", "格鲁吉亚语");
		language.put("gu", "古吉拉特语");
		language.put("kk", "哈萨克语");
		language.put("ht", "海地克里奥尔语");
		language.put("ko", "韩语");
		language.put("ha", "豪萨语");
		language.put("nl", "荷兰语");
		language.put("ky", "吉尔吉斯语");
		language.put("gl", "加利西亚语");
		language.put("ca", "加泰罗尼亚语");
		language.put("cs", "捷克语");
		language.put("kn", "卡纳达语");
		language.put("co", "科西嘉语");
		language.put("hr", "克罗地亚语");
		language.put("ku", "库尔德语");
		language.put("la", "拉丁语");
		language.put("lv", "拉脱维亚语");
		language.put("lo", "老挝语");
		language.put("lt", "立陶宛语");
		language.put("lb", "卢森堡语");
		language.put("ro", "罗马尼亚语");
		language.put("mg", "马尔加什语");
		language.put("mt", "马耳他语");
		language.put("mr", "马拉地语");
		language.put("ml", "马拉雅拉姆语");
		language.put("ms", "马来语");
		language.put("mk", "马其顿语");
		language.put("mi", "毛利语");
		language.put("mn", "蒙古语");
		language.put("bn", "孟加拉语");
		language.put("my", "缅甸语");
		language.put("hmn", "苗语");
		language.put("xh", "南非科萨语");
		language.put("zu", "南非祖鲁语");
		language.put("ne", "尼泊尔语");
		language.put("no", "挪威语");
		language.put("pa", "旁遮普语");
		language.put("pt", "葡萄牙语");
		language.put("ps", "普什图语");
		language.put("ny", "齐切瓦语");
		language.put("ja", "日语");
		language.put("sv", "瑞典语");
		language.put("sm", "萨摩亚语");
		language.put("sr", "塞尔维亚语");
		language.put("st", "塞索托语");
		language.put("si", "僧伽罗语");
		language.put("eo", "世界语");
		language.put("sk", "斯洛伐克语");
		language.put("sl", "斯洛文尼亚语");
		language.put("sw", "斯瓦希里语");
		language.put("gd", "苏格兰盖尔语");
		language.put("ceb", "宿务语");
		language.put("so", "索马里语");
		language.put("tg", "塔吉克语");
		language.put("te", "泰卢固语");
		language.put("ta", "泰米尔语");
		language.put("th", "泰语");
		language.put("tr", "土耳其语");
		language.put("cy", "威尔士语");
		language.put("ur", "乌尔都语");
		language.put("uk", "乌克兰语");
		language.put("uz", "乌兹别克语");
		language.put("es", "西班牙语");
		language.put("iw", "希伯来语");
		language.put("el", "希腊语");
		language.put("haw", "夏威夷语");
		language.put("sd", "信德语");
		language.put("hu", "匈牙利语");
		language.put("sn", "修纳语");
		language.put("hy", "亚美尼亚语");
		language.put("ig", "伊博语");
		language.put("it", "意大利语");
		language.put("yi", "意第绪语");
		language.put("hi", "印地语");
		language.put("su", "印尼巽他语");
		language.put("id", "印尼语");
		language.put("jw", "印尼爪哇语");
		language.put("en", "英语");
		language.put("yo", "约鲁巴语");
		language.put("vi", "越南语");
		language.put("zh", "中文");
		language.put("zh-TW", "中文_繁体");
		language.put("zh-CN", "中文_简体");
		return language;
	}

	private String getFromLang(FromLang fl) {
		Map<String, String> lang = loadLanguage();
		for (String k : lang.keySet()) {
			if (lang.get(k).equals(fl.toString())) {
				return k;
			}
		}
		return "en";
	}

	private String getToLang(ToLang tl) {
		Map<String, String> lang = loadLanguage();
		for (String k : lang.keySet()) {
			if (lang.get(k).equals(tl.toString())) {
				return k;
			}
		}
		return "zh";
	}

}
